﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using AvalonDock;
using Dotway.WPF.Panels;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace WIAssistant
{
    /// <summary>
    /// Interaction logic for Main.xaml
    /// </summary>
    public partial class Main : Window, IMain
    {
        private static Main _instance;
        private static readonly object _padlock = new object();

        private ContentPresenter _pickedWorkItemContentPresenter;

        public static Main Instance
        {
            get
            {
                lock (_padlock)
                {
                    if (_instance == null)
                    {
                        _instance = new Main();
                    }
                    return _instance;
                }
            }
        }

        private static void SetInstance(Main main)
        {
            lock (_padlock)
            {
                _instance = main;
            } 
        }

        public Main()
        {

            _mediator = new MainMediator(this);
            MainMediator.SetInstance(_mediator);

            InitializeComponent();
            SetInstance(this);
            _mediator.FillServerList();

            // Avalon Dock Stuff
            LeftSideBar.SelectedIndex = 0;
            RightSideBar.SelectedIndex = 0;
            ColorFactory.ChangeBrush(AvalonDockBrushes.DockablePaneTitleForeground, Brushes.Black);

            this.DataContext = _mediator;
        }

        private readonly MainMediator _mediator;

        #region Events
        private void btnRefresh_Click(object sender, RoutedEventArgs e)
        {
            _mediator.FillServerList();
        }

        // The user has selected a TFS Server.  Connect to it and populate the Projects list.
        private void cboServers_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            _mediator.ServerSelected();
        }

        private void lstProjects_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            _mediator.ProjectSelected();
        }



        private void lstQueries_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            
            _mediator.QuerySelected(sender);
        }

        private void lstProjects_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            LeftSideBar.SelectedIndex = 1;
        }


        private void lstQueryResults_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            _mediator.QueryResultsSelectionChanged(e);
        }
        
        private void PickWorkItem_Click(object sender, RoutedEventArgs e)
        {
            _mediator.PickWorkItemClicked(e);
        }

        private void CreateLinkClicked(object sender, RoutedEventArgs e)
        {
            _mediator.LinkPickedAndPad(true, e, LinkComment);
        }

        #endregion 


        #region Dependancy Properties
        public int PickedWorkItemID
        {
            get { return (int)GetValue(PickedWorkItemIDProperty); }
            set { SetValue(PickedWorkItemIDProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PickedWorkItemID.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PickedWorkItemIDProperty =
            DependencyProperty.Register("PickedWorkItemID", typeof(int), typeof(Main), new UIPropertyMetadata(0));
        
        //__________________________________
        // This is used so that we can get know when to enable and disable a row in the Query Results grid
        public bool IsCurrentItemEnabledChanged
        {
            get { return (bool)GetValue(IsCurrentItemEnabledChangedProperty); }
            set { SetValue(IsCurrentItemEnabledChangedProperty, value); }
        }

        public bool GetIsCurrentItemEnabledChanged(DependencyObject d)
        {
            return (bool)d.GetValue(IsCurrentItemEnabledChangedProperty);
        }
        public void SetIsCurrentItemEnabledChanged(DependencyObject d, bool value)
        {
            d.SetValue(IsCurrentItemEnabledChangedProperty, value);
        }
        public static readonly DependencyProperty IsCurrentItemEnabledChangedProperty = DependencyProperty.RegisterAttached("IsCurrentItemEnabledChanged", typeof(bool), typeof(Main), new UIPropertyMetadata(false, OnIsCurrentItemEnabledChanged));

        // This is static.  That is why we don't send it over to the mediator.  (Though I guess we could as a static method.)
        private static void OnIsCurrentItemEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListBoxItem listBoxItem = null;
            try
            {
                listBoxItem = (ListBoxItem)Main.Instance.lstQueryResults.ItemContainerGenerator.ContainerFromItem(((ContentPresenter)d).Content);
            }
            catch (InvalidCastException){}

            if (listBoxItem != null)
            {
                listBoxItem.IsSelected = false;
            }
            else
            {
                List<ListBoxItem> listBoxItems = new List<ListBoxItem>();
                foreach (IEnumerable<WorkItemColumnItem> boxItem in Main.Instance.lstQueryResults.SelectedItems)
                {
                    ListBoxItem item = (ListBoxItem)Main.Instance.lstQueryResults.ItemContainerGenerator.ContainerFromItem(boxItem);
                    if (item != null)
                        listBoxItems.Add(item);
                }
                foreach (ListBoxItem item in listBoxItems)
                {
                    item.IsSelected = false;
                }
            }
        }
        // End Disable row property stuff
        //__________________________________


        // This is the comment to be attached to the links
        public string LinkComment
        {
            get { return (string)GetValue(LinkCommentProperty); }
            set { SetValue(LinkCommentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LinkComment.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LinkCommentProperty =
            DependencyProperty.Register("LinkComment", typeof(string), typeof(Main), new UIPropertyMetadata(null));


        #endregion


        #region Implementation of IMain

        public String CurrentServer
        {
            get { return cboServers.SelectedItem.ToString(); }
            set { cboServers.SelectedItem = value; }
        }

        public ProjectInfo CurrentProject
        {
            get { return (ProjectInfo)lstProjects.SelectedItem; }
            set { lstProjects.SelectedItem = value; }
        }

        public IEnumerable ServerListSource
        {
            get { return cboServers.ItemsSource; }
            set { cboServers.ItemsSource = value; }
        }

        public IEnumerable ProjectListSource
        {
            get { return lstProjects.ItemsSource; }
            set { lstProjects.ItemsSource = value; }
        }

        public IEnumerable TeamQueryNamesListSource
        {
            get { return lstTeamQueries.ItemsSource; }
            set { lstTeamQueries.ItemsSource = value; }
        }

        public IEnumerable PersonalQueryNamesListSource
        {
            get { return lstPersonalQueries.ItemsSource; }
            set { lstPersonalQueries.ItemsSource = value; }
        }

        public IEnumerable QueryResultListSource
        {
            get { return lstQueryResults.ItemsSource; }
            set { lstQueryResults.ItemsSource = value; }
        }

        public object TabAddLinksDataContext
        {
            get { return tabAddLinks.DataContext; }
            set { tabAddLinks.DataContext = value; }
        }

        public object TabAddLinksContent
        {
            get { return tabAddLinks.Content; }
            set { tabAddLinks.Content = value; }
        }

        public void AddCanvasToPad(Canvas canvas)
        {
            if (!CanvasPad.Children.Contains(canvas))
                CanvasPad.Children.Add(canvas);
        }

        public void RemoveCanvasFromPad(Canvas canvas)
        {
            if (CanvasPad.Children.Contains(canvas))
                CanvasPad.Children.Remove(canvas);
        }


        // Sometimes we need the On Selected event to not be attached (like when we change the item source).
        //  This allows us to connect and disconnect it at will.
        public void ToggleOnSelectEvent(bool addEvent)
        {
            if (addEvent)
                lstQueryResults.SelectionChanged += lstQueryResults_SelectionChanged;
            else
                lstQueryResults.SelectionChanged -= lstQueryResults_SelectionChanged;
        }

        public void SelectQueryResultItem(WorkItem item)
        {
            // Because the ListBox only compares by reference, 
            //  we need to find the matching WorkItem (if any)
            //  before adding it to the selected list.
            IEnumerable<WorkItemColumnItem> matchingWorkItemInList = GetWorkItemColumnInQueryResultListByID(item.Id);
            if (matchingWorkItemInList != null)
                lstQueryResults.SelectedItems.Add(matchingWorkItemInList);
        }

        // Given an ID see if that id is currently in the ListBox.  If so then
        //  return it.  This is needed incase a WorkItem was found from a different query
        //  and thus has a different reference (even though it is the same WorkItem).
        // This since has found other uses as well.
        public WorkItem GetWorkItemInQueryResultListByID(int Id)
        {
            foreach (IEnumerable<WorkItemColumnItem> workItemColumns in lstQueryResults.Items)
            {
                if (workItemColumns.First().WorkItemForColumn.Id == Id)
                {
                    return workItemColumns.First().WorkItemForColumn;
                }
            }
            return null;
        }

        public IEnumerable<WorkItemColumnItem> GetWorkItemColumnInQueryResultListByID(int Id)
        {
            foreach (IEnumerable<WorkItemColumnItem> workItemColumns in lstQueryResults.Items)
            {
                if (workItemColumns.First().WorkItemForColumn.Id == Id)
                {
                    return workItemColumns;
                }
            }
            return null;
        }

        public void WindowRegisterName(string name, Geometry geometry)
        {
            RegisterName(name,geometry);
        }

        ZipperPanel IMain.CanvasPad
        {
            get { return CanvasPad; }
            set { throw new NotSupportedException("Testing Interface used"); }
        }

        #endregion

        public T GetWILinkElement<T>(string name) where T : DependencyObject
        {
            var templateKey = new DataTemplateKey(typeof (WorkItem));
            DataTemplate resource = (DataTemplate) FindResource(templateKey);
            var control = resource.FindName(name, _pickedWorkItemContentPresenter);

            return (T)control;

        }


        TextBlock IMain.WaitCursorText
        {
            get { return WaitCursorText; }
            set { throw new NotSupportedException("Testing Interface used"); }
        }

        Visibility IMain.WaitCursorVisibility
        {
            get { return WaitCursor.Visibility; }
            set { WaitCursor.Visibility = value; }
        }
        private void btnAddLinkComment_Checked(object sender, RoutedEventArgs e)
        {
            ToggleButton button = (ToggleButton)sender;
            Popup popup = (Popup)button.FindName("popAddCommentLink");
            popup.IsOpen = true;
        }

        private void btnAddLinkComment_Unchecked(object sender, RoutedEventArgs e)
        {
            ToggleButton button = (ToggleButton)sender;
            Popup popup = (Popup)button.FindName("popAddCommentLink");
            popup.IsOpen = false;
        }

        private void popAddCommentLink_Closed(object sender, EventArgs e)
        {
            DependencyObject dependencyObject = (DependencyObject)sender;
            ToggleButton button = dependencyObject.TryFindParent<ToggleButton>();
            button.IsChecked = false;
        }

        private void txtLinkComment_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                DependencyObject textBox = (DependencyObject) e.Source;
                Popup popup = textBox.TryFindParent<Popup>();
                popup.IsOpen = false;
            }

            // Testing
            GetWILinkElement<ItemsControl>("lstLinkList");
        }

        private void popAddCommentLink_Opened(object sender, EventArgs e)
        {
            Popup popup = (Popup) sender;
            ((TextBox) popup.FindName("txtLinkComment")).Focus();

        }

        private void PickedWorkItem_Loaded(object sender, RoutedEventArgs e)
        {
            _pickedWorkItemContentPresenter = (ContentPresenter) ((FrameworkElement) sender).TemplatedParent;
        }


        private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            _mediator.IterationSelectorItemChanged((IterationNode)((TreeView) sender).SelectedItem, e);
        }

        private void btnFindIterationChecked(object sender, RoutedEventArgs e)
        {
            ToggleButton button = (ToggleButton)sender;
            Popup popup = (Popup)button.FindName("popSelectIteration");
            try
            {
                popup.IsOpen = true;
            }
            catch (NullReferenceException)
            {
                MessageBox.Show(
                    "WI Assistant is unable to launch the Iterations Popup.  Please try again.  If the problem persists please restart the application.",
                    "Error");
            }
            
        }

        private void popSelectIteration_Closed(object sender, EventArgs e)
        {
            DependencyObject dependencyObject = (DependencyObject)sender;
            ToggleButton button = dependencyObject.TryFindParent<ToggleButton>();
            // This sets the toggle button to an up state (not the checkbox on the button)
            button.IsChecked = false;

            // Check to see if a path was selected
            CheckBox pathSelected = button.FindVisualChild<CheckBox>();
            if (pathSelected.IsChecked == true)
            {
                _mediator.ShowMoveTypes = Visibility.Visible;
            }
            else
            {
                _mediator.ShowMoveTypes = Visibility.Hidden;
            }

            MainMediator.OnMoveDestSelected();
        }

        private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            _mediator.ClearSelectedMoveIteration();

            Button button = (Button)sender;
            ToggleButton tglButton = button.TryFindParent<ToggleButton>();
            Popup popup = (Popup)tglButton.FindName("popSelectIteration");
            popup.IsOpen = false;
        }

        private void ManualMappingClick(object sender, RoutedEventArgs e)
        {

            _mediator.ManualMappingClick((WorkItemTypeMapping)((ContentControl) sender).DataContext);
           
        }

        private void SettingsWITDefaultColumn_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            object parameter = ((TreeView) sender).SelectedItem;
            if (parameter is WITSelectorProject)
                _mediator.SettingsWITDefaultColumnProjectSelected((WITSelectorProject)parameter, e);
        }

        private void DefaultFieldForWITChosen(object sender, SelectionChangedEventArgs e)
        {
            _mediator.WITSaveDefaultFieldsForToXML(CurrentServer);
        }



    }
}